import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
import java.util.Date;

public class Multibuffer extends JPanel implements KeyListener, MouseListener,
		MouseMotionListener, Runnable {
	private Image[] slike;
	private Dimension velicinaProzora;
	private boolean init;

	private double ugao;
	private int tekuciBafer;
	private final int brojBafera = 20;
	private AffineTransform transformacija = new AffineTransform();
	private Paint farbanje = new GradientPaint(-1, -1, Color.blue, 1, 1,
			Color.red);
	private Ellipse2D krug = new Ellipse2D.Double(-1, -1, 2, 2);

	private int korak=10;
	public Multibuffer() {
		addMouseListener(this);
		addMouseMotionListener(this);
	}

	private void init() {
		if (init)
			return;

		velicinaProzora = getSize();
		slike = new Image[brojBafera];
		for (int i = 0; i < brojBafera; i++) {
			slike[i] = createImage((int) velicinaProzora.getWidth(),
					(int) velicinaProzora.getHeight());
			Graphics2D g2d = (Graphics2D) slike[i].getGraphics();
			g2d.setRenderingHints(new RenderingHints(
					RenderingHints.KEY_ANTIALIASING,
					RenderingHints.VALUE_ANTIALIAS_ON));
			g2d.setPaint(Color.gray);
			g2d.fill(new Rectangle2D.Double(0, 0, velicinaProzora.getWidth(),
					velicinaProzora.getHeight()));
		}

		init = true;
	}

	public void paint(Graphics g) {
		Graphics2D g2d = (Graphics2D) g;
		if (!init)
			init();

		Graphics2D g2d_bafer = (Graphics2D) slike[tekuciBafer].getGraphics();
		double poluprecnik_x = velicinaProzora.getWidth() / 2;
		double poluprecnik_y = velicinaProzora.getHeight() / 2;

		transformacija.setToIdentity();
		transformacija.translate(poluprecnik_x, poluprecnik_y);
		transformacija.rotate(ugao);
		//transformacija.translate(50 + poluprecnik_y / 3 * Math.sin(ugao * 3)
		//		+ poluprecnik_y / 2 * Math.sin(ugao * 4), 0);
		transformacija.translate(korak, 0);
		transformacija.rotate(ugao);
		transformacija.scale(20, 20);

		g2d_bafer.setTransform(transformacija);
		g2d_bafer.setPaint(farbanje);
		g2d_bafer.fill(krug);

		g2d.drawImage(slike[tekuciBafer], 0, 0, this);
		tekuciBafer = (tekuciBafer + 1) % brojBafera;
		ugao += 0.05;
		korak=(korak+5)% (int)velicinaProzora.getHeight();
	}

	// KeyListener implementation
	public void keyPressed(KeyEvent e) {
		switch (e.getKeyCode()) {
		case KeyEvent.VK_UP:
			break;
		case KeyEvent.VK_DOWN:
			break;

		case KeyEvent.VK_LEFT:
			break;

		case KeyEvent.VK_RIGHT:
			break;
		}
	}

	public void keyReleased(KeyEvent e) {
	}

	public void keyTyped(KeyEvent e) {
	}

	// MouseListener implementation
	public void mouseClicked(MouseEvent e) {
	}

	public void mouseReleased(MouseEvent e) {
	}

	public void mouseExited(MouseEvent e) {
	}

	public void mousePressed(MouseEvent e) {
	}

	public void mouseEntered(MouseEvent e) {
	}

	// MouseMotionListener
	public void mouseMoved(MouseEvent e) {
	}

	public void mouseDragged(MouseEvent e) {
	}

	public void run() {
		long starttime;

		while (true) {
			starttime = System.currentTimeMillis();
			try {
				repaint();
				starttime += 40;
				Thread.sleep(Math.max(0, starttime - System.currentTimeMillis()));
			} catch (InterruptedException e) {
				break;
			}
		}
	}

	public static void main(String s[]) {
		Multibuffer panel = new Multibuffer();

		panel.setOpaque(true);

		JFrame frame = new JFrame("Multibuffer");
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});

		frame.getContentPane().add(panel);
		frame.setSize(new Dimension(800, 600));
		frame.setResizable(false);
		frame.setVisible(true);
		frame.addKeyListener(panel);

		Thread t = new Thread(panel);
		t.start();
	}
}